package java_thinking.unit_21._21_10;

import java_thinking.unit_21._21_2.Point;
import net.jcip.annotations.GuardedBy;

import java.util.HashSet;
import java.util.Set;

/**
 * @Desc:   10-5 在协作对象之间发生的死锁 警惕不要写出这样的代码 优化方案通过公开调用来避免 10-6
 * @author: cww
 * @DateTime: 2019/6/20 19:08
 */

public class CooperatingDeadlock {
    /**
     * 出租车，
     */
    class Taxi {
        @GuardedBy("this") private Point location, destination;
        private final Dispatcher dispatcher;

        public Taxi(Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
        }
        public synchronized Point getLocation() {
            return location;
        }

        /**
         * 更新出租车的当前地点，如果当前地点在调度范围内，则通知调度中心我到了，可以接受调度
         * 该方法会获得两个锁，先获得 Taxi 锁，再获得 Dispatcher
         * @param location
         */
        public synchronized void setLocation(Point location) {
            this.location = location;
            if (location.equals(destination)) {
                dispatcher.notifyAvailable(this);
            }
        }

        public synchronized Point getDestination() {
            return destination;
        }

        public synchronized void setDestination(Point destination) {
            this.destination = destination;
        }
    }

    /**
     * 调度
     */
    class Dispatcher {
        @GuardedBy("this") private final Set<Taxi> taxis;
        @GuardedBy("this") private final Set<Taxi> availableTaxis;

        public Dispatcher() {
            taxis = new HashSet<Taxi>();
            availableTaxis = new HashSet<Taxi>();
        }

        public synchronized void notifyAvailable(Taxi taxi) {
            availableTaxis.add(taxi);
        }

        /**
         * 该方法会获得两个锁，首先获取 Dispatcher 再获取每一个 Taxi 锁
         * @return
         */
        public synchronized Image getImage() {
            Image image = new Image();
            for (Taxi taxi :taxis) {
                image.drawMarker(taxi.getLocation());
            }
            return image;
        }
    }

    class Image {
        public void drawMarker(Point p) {
        }
    }

}
